using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class HoudiniCloudsShadowRenderPass : ScriptableRenderPass
{
    #region shaderId声明

    private const string KRenderTag = "Render Clouds Shadow"; // 会出现在Debugger中
    private static readonly int SkyModeId = Shader.PropertyToID("_sky_mode");
    private static readonly int DebugModeId = Shader.PropertyToID("_debug_mode");
    private static readonly int DebugIterationId = Shader.PropertyToID("_debug_iteration");
    private static readonly int CamFrustumId = Shader.PropertyToID("_CamFrustum");
    private static readonly int CamToWorldId = Shader.PropertyToID("_CamToWorld");
    private static readonly int AccuracyId = Shader.PropertyToID("_accuracy");
    private static readonly int IndexId = Shader.PropertyToID("_index");
    private static readonly int DataId = Shader.PropertyToID("_data");
    private static readonly int NoiseId = Shader.PropertyToID("_noise");

    private static readonly int SinId = Shader.PropertyToID("_sin");

    private static readonly int CornerInId = Shader.PropertyToID("_corner_in");
    private static readonly int CornerOutId = Shader.PropertyToID("_corner_out");
    private static readonly int DataUvAdjustId = Shader.PropertyToID("_data_uv_adjust");
    private static readonly int DataTexelId = Shader.PropertyToID("_data_texel");

    private static readonly int MovementId = Shader.PropertyToID("_movement");
    private static readonly int ClipPanelId = Shader.PropertyToID("_clip_panel");
    private static readonly int CloudScaleId = Shader.PropertyToID("_cloud_scale");

    private static readonly int Adjust8Id = Shader.PropertyToID("_adjust8");

    private static readonly int SkyColorId = Shader.PropertyToID("_sky_color");
    private static readonly int CloudColorId = Shader.PropertyToID("_cloud_color");
    private static readonly int ShadowParmId = Shader.PropertyToID("_shadow_parm");
    // private static readonly int EmissionColorId = Shader.PropertyToID("_emission_color");

    #endregion

    private HoudiniCloudsVolume _cloudsVolume;
    private RenderTargetIdentifier _source;

    private readonly Material _shadowMaterial;

    private readonly Shader _shadowShader = Shader.Find("MROP/RenderDepthTexture");

    // private readonly GameObject _light = GameObject.Find("Light");
    private readonly Camera _depthCamera = GameObject.Find("depthCamera").GetComponent<Camera>();

    public HoudiniCloudsShadowRenderPass(Material shadowMat)
    {
        _shadowMaterial = shadowMat;


        _depthCamera = SetDepthCamera(_depthCamera);
    }

    public void Setup(in RenderTargetIdentifier target) // 设置Target
    {
        _source = target;
    }

    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        if (_shadowMaterial == null)
        {
            Debug.Log("Material not create");
            return;
        }

        // 后处理效果是否生效
        if (!renderingData.cameraData.postProcessEnabled) return;

        // 通过队列检查Volume参数
        var stack = VolumeManager.instance.stack;
        _cloudsVolume = stack.GetComponent<HoudiniCloudsVolume>();
        if (_cloudsVolume == null) return;
        if (!_cloudsVolume.IsActive()) return;

        var cmd = CommandBufferPool.Get(KRenderTag);
        Render(cmd, renderingData);
        context.ExecuteCommandBuffer(cmd);
        CommandBufferPool.Release(cmd);
    }

    private void Render(CommandBuffer cmd, RenderingData rendingData)
    {
        #region ShadowHandle

        // _depthCamera.targetTexture = _cloudsVolume.shadowRt.value;
        _depthCamera.enabled = true;

        #endregion

        ParameterLogic(rendingData.cameraData);

        ClearOutRenderTexture(_depthCamera.targetTexture);
        cmd.Blit(null, _depthCamera.targetTexture, _shadowMaterial, 0);
        cmd.Blit(null, _source, _shadowMaterial, 0);
    }

    private static Matrix4x4 CamFrustum(CameraData cam)
    {
        Matrix4x4 frustum = Matrix4x4.identity;
        float size = cam.camera.orthographicSize;

        Vector3 goUp = Vector3.up * size;
        Vector3 goRight = Vector3.right * size * cam.camera.aspect;

        Vector3 topLeft = (-Vector3.forward - goRight + goUp);
        Vector3 topRight = (-Vector3.forward + goRight + goUp);
        Vector3 btmRight = (-Vector3.forward + goRight - goUp);
        Vector3 btmLeft = (-Vector3.forward - goRight - goUp);

        frustum.SetRow(0, topLeft);
        frustum.SetRow(1, topRight);
        frustum.SetRow(2, btmRight);
        frustum.SetRow(3, btmLeft);
        return frustum;
    }

    private Camera SetDepthCamera(Camera depthCamera)
    {
        depthCamera.orthographic = true;
        depthCamera.clearFlags = CameraClearFlags.SolidColor;
        depthCamera.backgroundColor = Color.white;
        return depthCamera;
    }

    private void ParameterLogic(CameraData cameraData)
    {
        // Debug
        _shadowMaterial.SetInt(SkyModeId, _cloudsVolume.skyMode.value ? 1 : 0);
        _shadowMaterial.SetInt(DebugModeId, _cloudsVolume.debugMode.value);
        _shadowMaterial.SetInt(DebugIterationId, _cloudsVolume.debugIteration.value ? 1 : 0);
        // 主摄像机相关
        _shadowMaterial.SetMatrix(CamFrustumId, CamFrustum(cameraData));
        _shadowMaterial.SetMatrix(CamToWorldId, cameraData.camera.cameraToWorldMatrix); //可以将右手坐标系下的相机空间坐标正确转换为左手坐标系下的世界空间坐标
        // 云的形状相关
        _shadowMaterial.SetFloat(CloudScaleId, _cloudsVolume.cloudScale.value);
        _shadowMaterial.SetFloat(AccuracyId, _cloudsVolume.accuracy.value);
        _shadowMaterial.SetTexture(IndexId, _cloudsVolume.index.value);
        _shadowMaterial.SetTexture(DataId, _cloudsVolume.data.value);
        _shadowMaterial.SetTexture(NoiseId, _cloudsVolume.noise.value);
        // _shadowMaterial.SetTexture(SinId, _cloudsVolume.sin.value);
        _shadowMaterial.SetVector(CornerInId, new Vector4(0,0,0,0));
        _shadowMaterial.SetVector(CornerOutId, new Vector3(_cloudsVolume.index.value.width, _cloudsVolume.index.value.height,_cloudsVolume.index.value.depth) * _cloudsVolume.highResScale.value * _cloudsVolume.cloudScale.value);
        _shadowMaterial.SetFloat(DataTexelId, 5.0f / _cloudsVolume.data.value.height);
        _shadowMaterial.SetVector(ClipPanelId, _cloudsVolume.clipPlane.value);
        _shadowMaterial.SetVector(MovementId, new Vector4(_cloudsVolume.sinSpeed.value, _cloudsVolume.sinStrength.value, _cloudsVolume.noiseSpeed.value, _cloudsVolume.noiseStrength.value));

        // 其他参数与Debug
        _shadowMaterial.SetVector(Adjust8Id, _cloudsVolume.colorAdjust.value);
        _shadowMaterial.SetVector(SkyColorId, _cloudsVolume.skyColor.value);
        _shadowMaterial.SetVector(CloudColorId, _cloudsVolume.cloudColor.value);
        _shadowMaterial.SetVector(ShadowParmId, new Vector4(_cloudsVolume.shadowStrength.value, 0, 0, 0));
    }

    public void ClearOutRenderTexture(RenderTexture renderTexture)
    {
        RenderTexture rt = RenderTexture.active;
        RenderTexture.active = renderTexture;
        GL.Clear(true, true, Color.clear);
        RenderTexture.active = rt;
    }
}